#pragma once

#include <iostream>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cerrno>
#include <cstring>
#include "Log.hpp"
#include "err.hpp"

const int default_socket = -1;

const int backlog = 32;

class Sock
{
public:
    Sock()
        : _sock(default_socket)
    {
    }

    void Socket()
    {
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_sock < 0)
        {
            LogMessage(Fatal, "creat socket fail , errno : %d , error : %s", errno, strerror(errno));
            exit(SOCK_ERR);
        }
        LogMessage(Info, "creat socket success");
    }

    void Bind(uint16_t &serverPort)
    {
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_port = htons(serverPort);
        if (bind(_sock, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            LogMessage(Fatal, "bind socket fail , errno : %d , error : %s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        LogMessage(Info, "bind socket success");
    }

    void Listen()
    {
        if (listen(_sock, backlog) < 0)
        {
            LogMessage(Fatal, "listen socket fail , errno : %d , error : %s", errno, strerror(errno));
            exit(LISTEN_ERR);
        }
        LogMessage(Info, "listen socket success");
    }

    int Accept(std::string *clientIp, uint16_t *clientPort)//输出型参数
    {
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        socklen_t len = sizeof(local);
        int sock = accept(_sock, (struct sockaddr *)&local, &len);
        if (sock < 0)
        {
            LogMessage(Fatal, "accept socket fail , errno : %d , error : %s", errno, strerror(errno));//注意，在EpollServer.hpp的Accepter函数中，第一次获取链接成功，sock大于0
            //exit(ACCEPT_ERR);                                                                       //第二次获取链接失败，sock小于0，此时，errno为11，表示连接没有准备好，才会跳出
        }                                                                                             //Accepter函数里面的循环，所以，这里的sock小于0，不能直接终止
        LogMessage(Info, "accept socket success");                                                      

        *clientIp = inet_ntoa(local.sin_addr);
        *clientPort = ntohs(local.sin_port);

        return sock;
    }

    void Connect(const std::string serverIp,const uint16_t serverPort)
    {
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = inet_addr(serverIp.c_str());
        local.sin_port = htons(serverPort);
        if(connect(_sock,(struct sockaddr*)&local,sizeof(local)) < 0)
        {
            LogMessage(Fatal, "connect socket fail , errno : %d , error : %s", errno, strerror(errno));
            exit(CONNECT_ERR);
        }
        LogMessage(Info, "connect socket success");
    }

    int Fd()
    {
        return _sock;
    }

    void Close()
    {
        if(_sock != default_socket)
        {
            close(_sock);
        }
    }

    ~Sock()
    {
    }

private:
    int _sock;
};


